﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

using NHibernate;
using NHibernate.Linq;
using Yala.Core.Domain;

namespace Yala.DataAccess.Common.Nhibernate {
    public abstract class NhRepositoryBase<T> : IRepository<T> where T : class, new() {

        private ISession _session;
        protected NhRepositoryBase(ISession session) {
            _session = session;
        }

        public virtual void Add(T item) {
            using(var txn = _session.BeginTransaction()) {
                try {
                    _session.Save(item);
                    _session.Flush();
                    txn.Commit();
                } catch {
                    txn.Rollback();
                    throw;
                }
            }
        }

        public virtual void Add(IEnumerable<T> items) {
            using(var txn = _session.BeginTransaction()) {
                try {
                    foreach(var item in items) {
                        _session.Save(item);
                    }
                    _session.Flush();
                    txn.Commit();
                } catch {
                    txn.Rollback();
                    throw;
                }
            }
        }

        public virtual void Update(T item) {
            using(var txn = _session.BeginTransaction()) {
                try {
                    _session.Update(item);
                    _session.Flush();
                    txn.Commit();
                } catch {
                    txn.Rollback();
                    throw;
                }
            }
        }

        public virtual void Delete(Expression<Func<T, bool>> expression) {
            using(var txn = _session.BeginTransaction()) {
                try {

                    var provider = _session.Query<T>()
                       .Where(expression).FirstOrDefault();

                    if(provider != null)
                        _session.Delete(provider);

                    _session.Flush();
                    txn.Commit();
                } catch {
                    txn.Rollback();
                    throw;
                }
            }
        }

        public virtual void Delete(T item) {
            using(var txn = _session.BeginTransaction()) {
                try {
                    _session.Delete(item);
                    _session.Flush();
                    txn.Commit();
                } catch {
                    txn.Rollback();
                    throw;
                }
            }
        }

        public virtual void DeleteAll() {
            throw new NotImplementedException();
        }

        public virtual void CommitChanges() {
            _session.Flush();
        }

        public virtual T Single(Expression<Func<T, bool>> expression) {
            using(var txn = _session.BeginTransaction()) {
                try {
                    var provider = _session.Query<T>()
                        .Where(expression).FirstOrDefault();
                    txn.Commit();
                    return provider;
                } catch {
                    txn.Rollback();
                    throw;
                }
            }
        }

        public virtual IQueryable<T> All() {
            using(var txn = _session.BeginTransaction()) {
                try {
                    var providers = _session.Query<T>();
                    txn.Commit();
                    return providers;
                } catch {
                    txn.Rollback();
                    throw;
                }
            }
        }

        public virtual void Dispose() {
            if(_session != null)
                _session.Close();//.Dispose();
        }
    }
}
